
/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#ifndef _NGX_HTTP_REQUEST_H_INCLUDED_
#define _NGX_HTTP_REQUEST_H_INCLUDED_


#define NGX_HTTP_MAX_URI_CHANGES 10
#define NGX_HTTP_MAX_SUBREQUESTS 50

/* must be 2^n */
#define NGX_HTTP_LC_HEADER_LEN 32


#define NGX_HTTP_DISCARD_BUFFER_SIZE   4096
#define NGX_HTTP_LINGERING_BUFFER_SIZE 4096


#define NGX_HTTP_VERSION_9  9
#define NGX_HTTP_VERSION_10 1000
#define NGX_HTTP_VERSION_11 1001
#define NGX_HTTP_VERSION_20 2000

#define NGX_HTTP_UNKNOWN   0x0001
#define NGX_HTTP_GET       0x0002
#define NGX_HTTP_HEAD      0x0004
#define NGX_HTTP_POST      0x0008
#define NGX_HTTP_PUT       0x0010
#define NGX_HTTP_DELETE    0x0020
#define NGX_HTTP_MKCOL     0x0040
#define NGX_HTTP_COPY      0x0080
#define NGX_HTTP_MOVE      0x0100
#define NGX_HTTP_OPTIONS   0x0200
#define NGX_HTTP_PROPFIND  0x0400
#define NGX_HTTP_PROPPATCH 0x0800
#define NGX_HTTP_LOCK      0x1000
#define NGX_HTTP_UNLOCK    0x2000
#define NGX_HTTP_PATCH     0x4000
#define NGX_HTTP_TRACE     0x8000

#if (NGX_HTTP_PROXY_CONNECT)
#define NGX_HTTP_CONNECT 0x10000
#endif

#define NGX_HTTP_CONNECTION_CLOSE      1
#define NGX_HTTP_CONNECTION_KEEP_ALIVE 2


#define NGX_NONE 1


#define NGX_HTTP_PARSE_HEADER_DONE 1

#define NGX_HTTP_CLIENT_ERROR            10
#define NGX_HTTP_PARSE_INVALID_METHOD    10
#define NGX_HTTP_PARSE_INVALID_REQUEST   11
#define NGX_HTTP_PARSE_INVALID_VERSION   12
#define NGX_HTTP_PARSE_INVALID_09_METHOD 13

#define NGX_HTTP_PARSE_INVALID_HEADER 14


/* unused                                  1 */
#define NGX_HTTP_SUBREQUEST_IN_MEMORY  2
#define NGX_HTTP_SUBREQUEST_WAITED     4
#define NGX_HTTP_SUBREQUEST_CLONE      8
#define NGX_HTTP_SUBREQUEST_BACKGROUND 16

#define NGX_HTTP_LOG_UNSAFE 1


#define NGX_HTTP_CONTINUE            100
#define NGX_HTTP_SWITCHING_PROTOCOLS 101
#define NGX_HTTP_PROCESSING          102

#define NGX_HTTP_OK              200
#define NGX_HTTP_CREATED         201
#define NGX_HTTP_ACCEPTED        202
#define NGX_HTTP_NO_CONTENT      204
#define NGX_HTTP_PARTIAL_CONTENT 206

#define NGX_HTTP_SPECIAL_RESPONSE   300
#define NGX_HTTP_MOVED_PERMANENTLY  301
#define NGX_HTTP_MOVED_TEMPORARILY  302
#define NGX_HTTP_SEE_OTHER          303
#define NGX_HTTP_NOT_MODIFIED       304
#define NGX_HTTP_TEMPORARY_REDIRECT 307
#define NGX_HTTP_PERMANENT_REDIRECT 308

#define NGX_HTTP_BAD_REQUEST  400
#define NGX_HTTP_UNAUTHORIZED 401
#define NGX_HTTP_FORBIDDEN    403
#define NGX_HTTP_NOT_FOUND    404
#define NGX_HTTP_NOT_ALLOWED  405

#if (NGX_HTTP_PROXY_CONNECT)
#define NGX_HTTP_PROXY_AUTHENTICATION_REQUIRED 407
#endif

#define NGX_HTTP_REQUEST_TIME_OUT         408
#define NGX_HTTP_CONFLICT                 409
#define NGX_HTTP_LENGTH_REQUIRED          411
#define NGX_HTTP_PRECONDITION_FAILED      412
#define NGX_HTTP_REQUEST_ENTITY_TOO_LARGE 413
#define NGX_HTTP_REQUEST_URI_TOO_LARGE    414
#define NGX_HTTP_UNSUPPORTED_MEDIA_TYPE   415
#define NGX_HTTP_RANGE_NOT_SATISFIABLE    416
#define NGX_HTTP_MISDIRECTED_REQUEST      421
#define NGX_HTTP_TOO_MANY_REQUESTS        429


/* Our own HTTP codes */

/* The special code to close connection without any response */
#define NGX_HTTP_CLOSE 444

#define NGX_HTTP_NGINX_CODES 494

#define NGX_HTTP_REQUEST_HEADER_TOO_LARGE 494

#define NGX_HTTPS_CERT_ERROR 495
#define NGX_HTTPS_NO_CERT    496

/*
 * We use the special code for the plain HTTP requests that are sent to
 * HTTPS port to distinguish it from 4XX in an error page redirection
 */
#define NGX_HTTP_TO_HTTPS 497

/* 498 is the canceled code for the requests with invalid host name */

/*
 * HTTP does not define the code for the case when a client closed
 * the connection while we are processing its request so we introduce
 * own code to log such situation when a client has closed the connection
 * before we even try to send the HTTP header to it
 */
#define NGX_HTTP_CLIENT_CLOSED_REQUEST 499


#define NGX_HTTP_INTERNAL_SERVER_ERROR 500
#define NGX_HTTP_NOT_IMPLEMENTED       501
#define NGX_HTTP_BAD_GATEWAY           502
#define NGX_HTTP_SERVICE_UNAVAILABLE   503
#define NGX_HTTP_GATEWAY_TIME_OUT      504
#define NGX_HTTP_VERSION_NOT_SUPPORTED 505
#define NGX_HTTP_INSUFFICIENT_STORAGE  507


#define NGX_HTTP_LOWLEVEL_BUFFERED 0xf0
#define NGX_HTTP_WRITE_BUFFERED    0x10
#define NGX_HTTP_GZIP_BUFFERED     0x20
#define NGX_HTTP_SSI_BUFFERED      0x01
#define NGX_HTTP_SUB_BUFFERED      0x02
#define NGX_HTTP_COPY_BUFFERED     0x04


typedef enum
{
    NGX_HTTP_INITING_REQUEST_STATE = 0,
    NGX_HTTP_READING_REQUEST_STATE,
    NGX_HTTP_PROCESS_REQUEST_STATE,

    NGX_HTTP_CONNECT_UPSTREAM_STATE,
    NGX_HTTP_WRITING_UPSTREAM_STATE,
    NGX_HTTP_READING_UPSTREAM_STATE,

    NGX_HTTP_WRITING_REQUEST_STATE,
    NGX_HTTP_LINGERING_CLOSE_STATE,
    NGX_HTTP_KEEPALIVE_STATE
} ngx_http_state_e;


typedef struct
{
    ngx_str_t                  name;
    ngx_uint_t                 offset;
    ngx_http_header_handler_pt handler;
} ngx_http_header_t;


typedef struct
{
    ngx_str_t  name;
    ngx_uint_t offset;
} ngx_http_header_out_t;


typedef struct
{
    ngx_list_t headers;

    ngx_table_elt_t *host;
    ngx_table_elt_t *connection;
    ngx_table_elt_t *if_modified_since;
    ngx_table_elt_t *if_unmodified_since;
    ngx_table_elt_t *if_match;
    ngx_table_elt_t *if_none_match;
    ngx_table_elt_t *user_agent;
    ngx_table_elt_t *referer;
    ngx_table_elt_t *content_length;
    ngx_table_elt_t *content_range;
    ngx_table_elt_t *content_type;

    ngx_table_elt_t *range;
    ngx_table_elt_t *if_range;

    ngx_table_elt_t *transfer_encoding;
    ngx_table_elt_t *te;
    ngx_table_elt_t *expect;
    ngx_table_elt_t *upgrade;

#if (NGX_HTTP_GZIP || NGX_HTTP_HEADERS)
    ngx_table_elt_t *accept_encoding;
    ngx_table_elt_t *via;
#endif

    ngx_table_elt_t *authorization;

    ngx_table_elt_t *keep_alive;

#if (NGX_HTTP_X_FORWARDED_FOR)
    ngx_array_t x_forwarded_for;
#endif

#if (NGX_HTTP_REALIP)
    ngx_table_elt_t *x_real_ip;
#endif

#if (NGX_HTTP_HEADERS)
    ngx_table_elt_t *accept;
    ngx_table_elt_t *accept_language;
#endif

#if (NGX_HTTP_DAV)
    ngx_table_elt_t *depth;
    ngx_table_elt_t *destination;
    ngx_table_elt_t *overwrite;
    ngx_table_elt_t *date;
#endif

#if (NGX_HTTP_PROXY_CONNECT)
    ngx_table_elt_t *proxy_authorization;
#endif

    ngx_str_t user;
    ngx_str_t passwd;

    ngx_array_t cookies;

    ngx_str_t server;
    off_t     content_length_n;
    time_t    keep_alive_n;

    unsigned connection_type : 2;
    unsigned chunked         : 1;
    unsigned msie            : 1;
    unsigned msie6           : 1;
    unsigned opera           : 1;
    unsigned gecko           : 1;
    unsigned chrome          : 1;
    unsigned safari          : 1;
    unsigned konqueror       : 1;
} ngx_http_headers_in_t;


typedef struct
{
    ngx_list_t headers;
    ngx_list_t trailers;

    ngx_uint_t status;
    ngx_str_t  status_line;

    ngx_table_elt_t *server;
    ngx_table_elt_t *date;
    ngx_table_elt_t *content_length;
    ngx_table_elt_t *content_encoding;
    ngx_table_elt_t *location;
    ngx_table_elt_t *refresh;
    ngx_table_elt_t *last_modified;
    ngx_table_elt_t *content_range;
    ngx_table_elt_t *accept_ranges;
    ngx_table_elt_t *www_authenticate;
    ngx_table_elt_t *expires;
    ngx_table_elt_t *etag;

#if (NGX_HTTP_PROXY_CONNECT)
    ngx_table_elt_t *proxy_authenticate;
#endif

    ngx_str_t *override_charset;

    size_t     content_type_len;
    ngx_str_t  content_type;
    ngx_str_t  charset;
    u_char    *content_type_lowcase;
    ngx_uint_t content_type_hash;

    ngx_array_t cache_control;
    ngx_array_t link;

    off_t  content_length_n;
    off_t  content_offset;
    time_t date_time;
    time_t last_modified_time;
} ngx_http_headers_out_t;


typedef void (*ngx_http_client_body_handler_pt)(ngx_http_request_t *r);

typedef struct
{
    ngx_temp_file_t                *temp_file;
    ngx_chain_t                    *bufs;
    ngx_buf_t                      *buf;
    off_t                           rest;
    off_t                           received;
    ngx_chain_t                    *free;
    ngx_chain_t                    *busy;
    ngx_http_chunked_t             *chunked;
    ngx_http_client_body_handler_pt post_handler;
} ngx_http_request_body_t;


typedef struct ngx_http_addr_conf_s ngx_http_addr_conf_t;

typedef struct
{
    ngx_http_addr_conf_t *addr_conf;
    ngx_http_conf_ctx_t  *conf_ctx;

#if (NGX_HTTP_SSL || NGX_COMPAT)
    ngx_str_t *ssl_servername;
#if (NGX_PCRE)
    ngx_http_regex_t *ssl_servername_regex;
#endif
#endif

    ngx_chain_t *busy;
    ngx_int_t    nbusy;

    ngx_chain_t *free;

    unsigned ssl            : 1;
    unsigned proxy_protocol : 1;
} ngx_http_connection_t;


typedef void (*ngx_http_cleanup_pt)(void *data);

typedef struct ngx_http_cleanup_s ngx_http_cleanup_t;

struct ngx_http_cleanup_s
{
    ngx_http_cleanup_pt handler;
    void               *data;
    ngx_http_cleanup_t *next;
};


typedef ngx_int_t (*ngx_http_post_subrequest_pt)(ngx_http_request_t *r,
                                                 void *data, ngx_int_t rc);

typedef struct
{
    ngx_http_post_subrequest_pt handler;
    void                       *data;
} ngx_http_post_subrequest_t;


typedef struct ngx_http_postponed_request_s ngx_http_postponed_request_t;

struct ngx_http_postponed_request_s
{
    ngx_http_request_t           *request;
    ngx_chain_t                  *out;
    ngx_http_postponed_request_t *next;
};


typedef struct ngx_http_posted_request_s ngx_http_posted_request_t;

struct ngx_http_posted_request_s
{
    ngx_http_request_t        *request;
    ngx_http_posted_request_t *next;
};


typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);
typedef void (*ngx_http_event_handler_pt)(ngx_http_request_t *r);


struct ngx_http_request_s
{
    uint32_t signature; /* "HTTP" */

    ngx_connection_t *connection;

    void **ctx;
    void **main_conf;
    void **srv_conf;
    void **loc_conf;

    ngx_http_event_handler_pt read_event_handler;
    ngx_http_event_handler_pt write_event_handler;

#if (NGX_HTTP_CACHE)
    ngx_http_cache_t *cache;
#endif

    ngx_http_upstream_t *upstream;
    ngx_array_t         *upstream_states;
    /* of ngx_http_upstream_state_t */

    ngx_pool_t *pool;
    ngx_buf_t  *header_in;

    ngx_http_headers_in_t  headers_in;
    ngx_http_headers_out_t headers_out;

    ngx_http_request_body_t *request_body;

    time_t     lingering_time;
    time_t     start_sec;
    ngx_msec_t start_msec;
#if (T_NGX_RET_CACHE)
    ngx_usec_t start_usec;
#endif

    ngx_uint_t method;
    ngx_uint_t http_version;

    ngx_str_t request_line;
#if (T_NGX_VARS)
    ngx_str_t raw_uri;
#endif
    ngx_str_t uri;
    ngx_str_t args;
    ngx_str_t exten;
    ngx_str_t unparsed_uri;

#if (NGX_HTTP_PROXY_CONNECT)
    ngx_str_t connect_host;
    ngx_str_t connect_port;
    in_port_t connect_port_n;
    u_char   *connect_host_start;
    u_char   *connect_host_end;
    u_char   *connect_port_end;
#endif

    ngx_str_t method_name;
    ngx_str_t http_protocol;
    ngx_str_t schema;

    ngx_chain_t                  *out;
    ngx_http_request_t           *main;
    ngx_http_request_t           *parent;
    ngx_http_postponed_request_t *postponed;
    ngx_http_post_subrequest_t   *post_subrequest;
    ngx_http_posted_request_t    *posted_requests;

    ngx_int_t           phase_handler;
    ngx_http_handler_pt content_handler;
    ngx_uint_t          access_code;

    ngx_http_variable_value_t *variables;

#if (NGX_PCRE)
    ngx_uint_t ncaptures;
    int       *captures;
    u_char    *captures_data;
#endif

    size_t limit_rate;
    size_t limit_rate_after;

    /* used to learn the Apache compatible response length without a header */
    size_t header_size;

    off_t request_length;

    ngx_uint_t err_status;

    ngx_http_connection_t *http_connection;
    ngx_http_v2_stream_t  *stream;

    ngx_http_log_handler_pt log_handler;

    ngx_http_cleanup_t *cleanup;

    unsigned count       : 16;
    unsigned subrequests : 8;
    unsigned blocked     : 8;

    unsigned aio : 1;

    unsigned http_state : 4;

    /* URI with "/." and on Win32 with "//" */
    unsigned complex_uri : 1;

    /* URI with "%" */
    unsigned quoted_uri : 1;

    /* URI with "+" */
    unsigned plus_in_uri : 1;

    /* URI with " " */
    unsigned space_in_uri : 1;

    unsigned invalid_header : 1;

    unsigned add_uri_to_alias   : 1;
    unsigned valid_location     : 1;
    unsigned valid_unparsed_uri : 1;
    unsigned uri_changed        : 1;
    unsigned uri_changes        : 4;

    unsigned request_body_in_single_buf      : 1;
    unsigned request_body_in_file_only       : 1;
    unsigned request_body_in_persistent_file : 1;
    unsigned request_body_in_clean_file      : 1;
    unsigned request_body_file_group_access  : 1;
    unsigned request_body_file_log_level     : 3;
    unsigned request_body_no_buffering       : 1;

    unsigned subrequest_in_memory : 1;
    unsigned waited               : 1;

#if (NGX_HTTP_CACHE)
    unsigned cached : 1;
#endif

#if (NGX_HTTP_GZIP)
    unsigned gzip_tested : 1;
    unsigned gzip_ok     : 1;
    unsigned gzip_vary   : 1;
#endif

#if (NGX_PCRE)
    unsigned realloc_captures : 1;
#endif

    unsigned proxy        : 1;
    unsigned bypass_cache : 1;
    unsigned no_cache     : 1;

    /*
     * instead of using the request context data in
     * ngx_http_limit_conn_module and ngx_http_limit_req_module
     * we use the bit fields in the request structure
     */
    unsigned limit_conn_status : 2;
    unsigned limit_req_status  : 3;

    unsigned limit_rate_set       : 1;
    unsigned limit_rate_after_set : 1;
#if (T_NGX_HTTP_SYSGUARD)
    unsigned sysguard_set : 1;
#endif

#if 0
    unsigned                          cacheable:1;
#endif

    unsigned pipeline         : 1;
    unsigned chunked          : 1;
    unsigned header_only      : 1;
    unsigned expect_trailers  : 1;
    unsigned keepalive        : 1;
    unsigned lingering_close  : 1;
    unsigned discard_body     : 1;
    unsigned reading_body     : 1;
    unsigned internal         : 1;
    unsigned error_page       : 1;
    unsigned filter_finalize  : 1;
    unsigned post_action      : 1;
    unsigned request_complete : 1;
    unsigned request_output   : 1;
    unsigned header_sent      : 1;
    unsigned expect_tested    : 1;
    unsigned root_tested      : 1;
    unsigned done             : 1;
    unsigned logged           : 1;

    unsigned buffered : 4;

    unsigned main_filter_need_in_memory : 1;
    unsigned filter_need_in_memory      : 1;
    unsigned filter_need_temporary      : 1;
    unsigned preserve_body              : 1;
    unsigned allow_ranges               : 1;
    unsigned subrequest_ranges          : 1;
    unsigned single_range               : 1;
    unsigned disable_not_modified       : 1;

#if (NGX_STAT_STUB)
    unsigned stat_reading : 1;
    unsigned stat_writing : 1;
#endif
    unsigned stat_processing : 1;

    unsigned background   : 1;
    unsigned health_check : 1;

    /* used to parse HTTP headers */

    ngx_uint_t state;

    ngx_uint_t header_hash;
    ngx_uint_t lowcase_index;
    u_char     lowcase_header[NGX_HTTP_LC_HEADER_LEN];

    u_char *header_name_start;
    u_char *header_name_end;
    u_char *header_start;
    u_char *header_end;

    /*
     * a memory that can be reused after parsing a request line
     * via ngx_http_ephemeral_t
     */

    u_char *uri_start;
    u_char *uri_end;
    u_char *uri_ext;
    u_char *args_start;
    u_char *request_start;
    u_char *request_end;
    u_char *method_end;
    u_char *schema_start;
    u_char *schema_end;
    u_char *host_start;
    u_char *host_end;
    u_char *port_start;
    u_char *port_end;

    unsigned http_minor : 16;
    unsigned http_major : 16;

#if (T_NGX_MULTI_UPSTREAM)
    ngx_queue_t *multi_item;
    ngx_queue_t *backend_r;
    ngx_queue_t  waiting_queue;
    ngx_flag_t   waiting;
#endif
};


typedef struct
{
    ngx_http_posted_request_t terminal_posted_request;
} ngx_http_ephemeral_t;


#define ngx_http_ephemeral(r) (void *)(&r->uri_start)


extern ngx_http_header_t     ngx_http_headers_in[];
extern ngx_http_header_out_t ngx_http_headers_out[];


#define ngx_http_set_log_request(log, r) \
    ((ngx_http_log_ctx_t *)log->data)->current_request = r


#endif /* _NGX_HTTP_REQUEST_H_INCLUDED_ */
